package org.zero.codec.random;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.SneakyThrows;

import java.security.SecureRandom;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;

/**
 * @author Zero (cnzeropro@qq.com)
 * @since 2022/6/20
 */
@AllArgsConstructor
@Getter
public class RandomHelper {
    /**
     * 用于随机选的数字
     */
    public static final String BASE_NUMBER = "0123456789";
    /**
     * 用于随机选的字母
     */
    public static final String BASE_LETTER = "abcdefghijklmnopqrstuvwxyz";

    /**
     * 用于随机选的字符
     */
    public static final String BASE_CHAR = "~!@#$%^&*_-+=";

    /**
     * 用于随机选的字母和数字，默认只有字母小写
     */
    public static final String BASE_LETTER_NUMBER = BASE_LETTER + BASE_NUMBER;

    /**
     * 用于随机选的字母和数字，包含字母大写
     */
    public static final String BASE_LETTER_NUMBER_WITH_UPPER = BASE_LETTER.toUpperCase() + BASE_LETTER_NUMBER;

    /**
     * 用于随机选的字符、字母和数字，默认只有字母小写
     */
    public static final String BASE_CHAR_LETTER_NUMBER = BASE_LETTER_NUMBER + BASE_CHAR;

    /**
     * 用于随机选的字符、字母和数字，包含字母大写
     */
    public static final String BASE_CHAR_LETTER_NUMBER_WITH_UPPER = BASE_LETTER_NUMBER_WITH_UPPER + BASE_CHAR;

    /**
     * 持有的Random实例
     */
    private Random random;

    /**
     * 根据RandomType获取Random实例
     */
    public static Random obtainRandom(RandomType randomType) {
        switch (randomType) {
            case RANDOM:
                return obtainRandom();
            case THREAD_LOCAL_RANDOM:
                return obtainThreadLocalRandom();
            case SECURE_RANDOM:
                return obtainSecureRandom();
            default:
                return null;
        }
    }

    /**
     * 获取Random实例
     */
    public static Random obtainRandom() {
        return new Random();
    }

    /**
     * 获取ThreadLocalRandom实例
     */
    public static ThreadLocalRandom obtainThreadLocalRandom() {
        return ThreadLocalRandom.current();
    }

    /**
     * 获取SecureRandom实例
     */
    public static SecureRandom obtainSecureRandom() {
        return new SecureRandom();
    }

    /**
     * 获取强SecureRandom实例
     */
    @SneakyThrows
    public static SecureRandom obtainStrongRandom() {
        return SecureRandom.getInstanceStrong();
    }

    /**
     * 根据随机算法获取SecureRandom实例
     */
    @SneakyThrows
    public static SecureRandom obtainRandom(RandomAlgorithm algorithm) {
        return SecureRandom.getInstance(algorithm.getAlgorithm());
    }

    /**
     * 获取随机字符
     */
    public char randomChar() {
        return BASE_CHAR_LETTER_NUMBER_WITH_UPPER.charAt(random.nextInt(BASE_CHAR_LETTER_NUMBER_WITH_UPPER.length()));
    }

    /**
     * 获取随机字符串
     */
    public String randomString(int size) {
        return randomString(size, BASE_CHAR_LETTER_NUMBER_WITH_UPPER);
    }

    /**
     * 获取随机字符串
     */
    public String randomString(int size, String baseStr) {
        return random.ints(size, 0, baseStr.length())
                .mapToObj(i -> String.valueOf(baseStr.charAt(i)))
                .collect(Collectors.joining());
    }

    /**
     * 获取随机中文字符
     */
    public char randomChinese() {
        return (char) randomInt('\u4E00', '\u9FFF');
    }

    /**
     * 获取随机中文字符串
     */
    public String randomChineseString(int size) {
        return random.ints(size, '\u4E00', '\u9FFF')
                .mapToObj(i -> String.valueOf((char) i))
                .collect(Collectors.joining());
    }

    /**
     * 获取指定范围的随机整数
     */
    public int randomInt(int min, int max) {
        return random.nextInt(max - min) + min;
    }
}
